package com.iflytek.cosmo.ocr.common.web;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

import com.iflytek.cosmo.ocr.common.exception.BaseException;
import com.iflytek.cosmo.ocr.model.domain.MessageOutput;
import com.iflytek.cosmo.ocr.model.domain.State;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import static com.iflytek.cosmo.ocr.common.constant.CommonConstant.FAIL_CODE;

/**
 * Controller层统一异常处理类
 *
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019/3/4 14:46
 */
@ControllerAdvice
public class ExpcetionHandler {
    private static final Logger logger = LoggerFactory.getLogger(ExpcetionHandler.class);

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public MessageOutput<?> handleAllException(HttpServletRequest req, Throwable e) {
        StringBuffer requestURL = req.getRequestURL();
        String queryString = req.getQueryString();
        if (StringUtils.isNotBlank(queryString)) {
            requestURL.append("?").append(queryString);
        }
        logger.warn("Controller层请求异常, request: {} {}, exception: {}", req.getMethod(), requestURL, e.getMessage());

        if (e instanceof MethodArgumentNotValidException) {
            return buildInvalidArgumentResponse((MethodArgumentNotValidException) e);
        }
        else if (e instanceof MissingServletRequestParameterException) {
            return buildMissServletParamResponse((MissingServletRequestParameterException) e);
        }
        else if (e instanceof BaseException) {
            return buildCustomErrorResponse((BaseException) e);
        }

        logger.error("Controller层抛出未知异常", e);
        return getMessageOutput(e.getMessage());
    }

    /** 接口必填参数缺少 */
    private MessageOutput<?> buildMissServletParamResponse(MissingServletRequestParameterException e) {
        logger.info("请求缺少参数");
        return getMessageOutput(e.getMessage());
    }

    private MessageOutput<?> getMessageOutput(String message) {
        String errorMsg = message;
        State state = new State(FAIL_CODE);
        state.setFailed(errorMsg);
        return new MessageOutput(state);
    }

    /** 业务异常 */
    private MessageOutput<?> buildCustomErrorResponse(BaseException e) {
        logger.warn("Controller层抛出业务异常.", e);
        return getMessageOutput(e.getMessage());
    }

    /** SpringMVC 参数验证未通过 */
    private MessageOutput<?> buildInvalidArgumentResponse(MethodArgumentNotValidException e) {
        logger.warn("参数验证未通过.", e);
        BindingResult bindingResult = e.getBindingResult();
        if (bindingResult == null) {
            return getMessageOutput("参数验证未通过");
        }

        List<ObjectError> errorList = bindingResult.getAllErrors();
        if (CollectionUtils.isEmpty(errorList)) {
            return getMessageOutput("参数验证未通过");
        }

        String errorMessages = errorList.stream().map(ObjectError::getDefaultMessage).filter(StringUtils::isNotBlank)
                .collect(Collectors.joining("; "));
        return getMessageOutput(errorMessages);
    }

}
